﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
using System;
using System.IO;

namespace PengLuaKit
{
    //
    // @toLua interface
    //
    public class xLuaManager : MonoBehaviour
    {
        private static xLuaManager mInstance = null;
        
        public static xLuaManager Instance
        {
             get
            {
                return mInstance;
            }
        }

        private XLua.LuaEnv lua;
        public Action OnLuaPrepareWellHandler;
        
        void Awake()
        {
            mInstance = this;

            lua = new XLua.LuaEnv();
            LoadCommonLibs();
        }
        
        void LoadCommonLibs()
        {
            //
        }

        // Use this for initialization
        void Start()
        {
            // todo: when in publish env, this path will change
            lua.AddLoader( (ref string filePath) => { return MyCustomLoader(filePath); } );

#if UNITY_EDITOR
            AddSearchPath(Application.dataPath + "/PengxLuaKit");
            AddSearchPath(Application.dataPath + "/PengxLuaKit/Lua");
            AddSearchPath(Application.dataPath + "/ToLua/Lua");
#else
            AddSearchPath(Application.persistentDataPath + "/PengLuaKit");
            AddSearchPath(Application.persistentDataPath + "/PengLuaKit/Lua");
            AddSearchPath(Application.dataPath + "ToLua/Lua");
#endif

            // load gobal libray
            // todo

            if (OnLuaPrepareWellHandler != null)
                OnLuaPrepareWellHandler();
        }

        private List<string> mSearchPathList = new List<string>();
        [CSharpCallLua]
        public void AddSearchPath(string searchFolder)
        {
            if (!Path.IsPathRooted(searchFolder))
            {
                throw new Exception("Add a bad search abosulate path, path="+ searchFolder);
            }

            // convert path spliter
            searchFolder = searchFolder.Replace("\\", "/");
            if (searchFolder.Length > 0 && searchFolder.LastIndexOf("/") != 0)
                searchFolder += "/";

            searchFolder += "?.lua";
            if (!mSearchPathList.Contains(searchFolder))
            {
                mSearchPathList.Add(searchFolder);
                Debug.Log("searchFolder="+searchFolder); 
            }
        }

        private string FindFileAbsolutePath(string fileName)
        {
            if (Path.IsPathRooted(fileName))
                return fileName;

            if (fileName.EndsWith(".lua"))
                fileName = fileName.Substring(0, fileName.Length - 4);

            foreach (var itemFolder in mSearchPathList)
            {
                string itemPath = itemFolder.Replace("?", fileName);
                if (File.Exists(itemPath))
                {
                    Debug.Log("Get a absolute lua file path, path="+itemPath);
                    return itemPath;
                }
            }

            return null;
        }

        private byte[] MyCustomLoader(string fileName)
        {
            fileName = fileName.Replace(".", "/");// remove to /

            byte[] bytes = new byte[1];
            string absolutePath = FindFileAbsolutePath(fileName);
            if (!string.IsNullOrEmpty(absolutePath))
            {
                bytes = File.ReadAllBytes(absolutePath);
                Debug.Log("Load lua file content, bytes=" + bytes.Length + ", path=" + absolutePath);
            }
            return bytes;
        }

        #region lua load file, call lua function api

        public void DoFile(string filename)
        {
            filename = filename.Replace(".lua", "");
            filename = string.Format("require '{0}'", filename);
            lua.DoString(filename);
        }

        // Update is called once per frame
        public object[] CallFunction(string funcName, params object[] args)
        {
            LuaFunction func = lua.Global.Get<LuaFunction>(funcName);
            return null;
        }

        public LuaFunction GetFunction(string funcName)
        {
            return lua.Global.Get<LuaFunction>(funcName);
        }

#endregion

        public void LuaGC()
        {
            lua.GC();
        }

        void OnDestroy()
        {
            lua.Dispose();
            lua = null;
        }

    }
}